const t = {
  obj: (obj) => {
    if (!obj) return "";
    const form = [];
    Object.keys(obj).forEach(i => {
      if (obj[i] != undefined)
        form.push(i + "=" + encodeURIComponent(obj[i]));
    })
    return form.join("&");
  },
  form: (obj) => {
    if (!obj) return undefined;
    const form = new FormData();
    Object.keys(obj).forEach(i => {
      form.append(i, obj[i]);
    })
    return form;
  },
  /** 后端接口的URL */
  url: 'http://crossentropy.asia:8088',
  /** 状态码对应错误信息，错误码和错误信息的对象会回调给event.onerror事件 */
  error: { 0: '请求已中止' },

  /**
    * @typedef RequestEvent
    * @type {Object}
    * @property {function(XMLHttpRequest)} onopen - 请求准备发送时的事件
    * @property {function(XMLHttpRequest)} onloading - 请求正在加载的事件(readyState = 3)
    * @property {function(XMLHttpRequest)} oncomplete - 请求完成时的事件(readyState = 4)
    * @property {function(XMLHttpRequest)} onsuccess - 请求成功的事件(readyState = 4 && status == 200 && !response.errCode)
    * @property {function({ errCode: number, errMsg: string })} onerror - 请求发生错误时的事件(readyState = 4 && (status != 200 || response.errCode))
    * @property {function(ProgressEvent)} onprogress - 上传文件请求的进度事件
    */

  /** @type {RequestEvent} */
  event: {},
  /** 本次接口请求的临时事件，onprogress以外的全局事件任然会触发，临时事件优先于全局事件触发
   * @param {RequestEvent} event
   */
  eventonce(event) {
    this.__event = Object.assign({}, this.__event, event);
    return this;
  },
  /**
   * 发送接口
   * @param {string} url 接口地址
   * @param {XMLHttpRequestBodyInit | null} data 
   * @param {('POST' | 'GET')} [method='POST']
   */
  send(url, data, method = 'POST') {
    return new Promise((resolve, reject) => {
      const req = new XMLHttpRequest();
      req.onreadystatechange = async () => {
        if (req.readyState == 4) {
          this.__event?.oncomplete?.(req) | this.event.oncomplete?.(req);
          if (req.status == 200) {
            let obj = null;
            switch (req.responseType) {
              case 'text': if (req.response) obj = JSON.parse(req.responseText); break;
              case 'blob':
                if (req.response.type == 'text/plain') await req.response.text().then((value) => obj = JSON.parse(value));
                else obj = req.response;
                break;
            }
            if (obj && obj.errCode) {
              this.__event?.onerror?.(obj) | this.event.onerror?.(obj) | reject(obj);
            } else {
              this.__event?.oncomplete?.(obj) | this.event.oncomplete?.(obj) | resolve(obj);
            }
          } else {
            let error = { errCode: req.status };
            error.errMsg = this.error[req.status] || req.statusText;
            this.__event?.onerror?.(error) | this.event.onerror?.(error) | reject(error);
          }
        }
        else if (req.readyState == 3) this.__event?.onloading?.(req) | this.event.onloading?.(req);
      }
      req.open(method, this.url + url, true);
      req.upload.onprogress = this.__event?.onprogress || this.event.onprogress;
      req.responseType = 'text';
      if (this.__event?.onopen) this.__event.onopen(req);
      else req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8');
      this.event.onopen?.(req);
      req.send(data);
    });
  },
  sms_valid_code(obj) {
    return this.send("/sms_valid_code", this.obj(obj));
  },
  login_separate(obj) {
    return this.send("/login_separate", this.obj(obj));
  },
  register(obj) {
    return this.send("/user_register", this.obj(obj))
  },
  question(question) {
    return this.send("/question", "question=" + encodeURIComponent(question))
  },
  streamping() {
    return this.send("/streamping", undefined, 'GET');
  },
}

export default t;